package com.me.mysqladmin.util;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.sql.RowSet;
import javax.sql.rowset.CachedRowSet;

import com.me.mysqladmin.customize.IgnoreCaseMap;
import com.me.mysqladmin.util.BeanUtil;
import com.me.mysqladmin.util.NullUtil;
import com.sun.rowset.CachedRowSetImpl;
import com.sun.rowset.JdbcRowSetImpl;

@SuppressWarnings("restriction")
public class RowSetUtil {
	/**
	 * <p>执行SQL查询操作，返回离线结果集</p>
	 * @param pstmt SQL预编译对象
	 * @return		离线结果集
	 */
	public static RowSet executeQuery(PreparedStatement pstmt) throws SQLException{
		// 封装返回值
		CachedRowSet rowset = new CachedRowSetImpl();
		// 方法入参判断
		if (NullUtil.isNull(pstmt)) {
			return rowset;
		}
		// 获取在线结果集
		ResultSet rs = pstmt.executeQuery();
		// 将在线结果集转成离线结果集
		rowset.populate(rs);
		// 释放资源
		JDBCUtil.free(rs, pstmt);
		// 返回离线结果集
		return rowset;
	}
	
	/**
	 * <p>将离线结果集转换为List集合，集合中存放着一条条记录</p>
	 * <p>每条记录都是一个Map集合，其中key为列名，value为列值</p>
	 * @param rs 结果集对象
	 * @return List集合
	 */
	public static List<Map<String, Object>> toMapList(RowSet rs) {
		// 方法入参判断
		if (NullUtil.isNull(rs) || rs instanceof JdbcRowSetImpl) {
			return Collections.emptyList();
		}
		//封装返回值
		List<Map<String, Object>> mapList = new ArrayList<Map<String,Object>>();
		//解析结果集
		try {
			// 获取结果集的列数
			ResultSetMetaData rsmd = rs.getMetaData();
			int cols = rsmd.getColumnCount();
			// 获取结果集的行数
			int rows = getRowCount(rs);
			if(rows == 0){
				// 封装一行的记录
				Map<String, Object> rowMap = new IgnoreCaseMap<>();
				// 获取结果集的列名
				List<String> names = getColNames(rs);
				for(String name : names){
					rowMap.put(name, null);
				}
				mapList.add(rowMap);
			}
			// 初始化结果集游标位置
			rs.absolute(-1);
			while (rs.next()) {
				// 封装一行的记录
				Map<String, Object> rowMap = new IgnoreCaseMap<>();
				for (int i = 1; i <= cols; i++) {
					rowMap.put(rsmd.getColumnName(i), rs.getObject(i));
				}
				mapList.add(rowMap);
			}
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException("解析离线结果集失败！");
		}
		return mapList;
	}
	
	/**
	 * 获取结果集的列名称
	 * @param rs	离线结果集
	 * @return		列名集合
	 */
	private static List<String> getColNames(RowSet rs) {
		// 封装返回值
		List<String> colNames = new ArrayList<>();
		try {
			// 获取结果集的列数（下标从1开始）
			ResultSetMetaData rsmd = rs.getMetaData();
			int cols = rsmd.getColumnCount();
			for(int i = 1 ; i <= cols; i++){
				colNames.add(rsmd.getColumnName(i));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return colNames;
	}

	/**
	 * 获取结果集的行数
	 * @param rs	离线结果集
	 * @return		行数
	 */
	private static int getRowCount(RowSet rs) {
		// 行数记录器
		int count = 0;
		try {
			// 初始化结果集游标位置
			rs.absolute(-1);
			while (rs.next()) {
				count++;
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return count;
	}

	/**
	 * <p>将离线结果集转换为List集合，集合中存放着一条条记录</p>
	 * <p>每条记录都是一个Map集合，其中key为列的编号1,2,3,……,value为对应的列值</p>
	 * @param rs 离线结果集
	 * @return List集合
	 */
	public static List<Map<Integer, Object>> toSimpleMapList(RowSet rs) {
		// 方法入参判断
		if (NullUtil.isNull(rs)) {
			return Collections.emptyList();
		}
		try {
			// 获取列数
			int cols = rs.getMetaData().getColumnCount();
			return toSimpleMapList(rs, cols);
		} catch (SQLException e) {
			e.printStackTrace();
			throw new RuntimeException("解析离线结果集失败！");
		}
	}
	
	/**
	 * <p>将离线结果集的前N列转换为List集合，集合中存放着一条条记录</p>
	 * <p>每条记录都是一个Map集合，其中key为列的编号1,2,3,……,maxCol，value为对应的列值</p>
	 * @param rs 离线结果集
	 * @param maxCol 指定最大列数
	 * @return List集合
	 */
	public static List<Map<Integer, Object>> toSimpleMapList(RowSet rs , int maxCol) {
		// 方法入参判断
		if (NullUtil.isNull(rs) || maxCol < 1) {
			return Collections.emptyList();
		}
		// 封装返回值
		List<Map<Integer, Object>> mapList = new ArrayList<Map<Integer, Object>>();
		// 将结果集中的数据存入集合中
		try{
			// 初始化结果集游标位置
			rs.absolute(-1);
			while (rs.next()) {
				// 封装一行的记录
				Map<Integer, Object> map = new HashMap<Integer, Object>();
				for (int i = 1; i <= maxCol; i++) {
					map.put(i, rs.getObject(i));
				}
				mapList.add(map);
			}
		} catch(SQLException e){
			e.printStackTrace();
			throw new RuntimeException("解析离线结果集失败！");
		}
		return mapList;
	}
	
	/**
	 * 将数据库查询结果集转换为指定类型的实体集
	 * @param rs
	 * @param acceptType
	 * @return 实体集
	 */
	public static <T> List<T> toEntiyList(RowSet rs, Class<T> acceptType){
		return BeanUtil.toBeanList(toMapList(rs), acceptType);
	}
}
